//============================================================================
// Name        : fg.h
// Authors     : Luca Fabbrini, Giulio Giovannetti
// Version     : 1.0
// Date        : 10/02/2009
// Copyright   : Copyright (C) 2009 Universita' degli Studi di Firenze
// Licence     : This program is free software; you can redistribute it and/or
//               modify it under the terms of the GNU General Public License
//               as published by the Free Software Foundation; either version 2
//               of the License, or (at your option) any later version.
//
//               This program is distributed in the hope that it will be useful,
//               but WITHOUT ANY WARRANTY; without even the implied warranty of
//               MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//               GNU General Public License for more details.
//
//               You should have received a copy of the GNU General Public License
//               along with this program; if not, write to the Free Software
//               Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// Description : FG MANET routing module.
//============================================================================



#ifndef FG_H_
#define FG_H_


#include <omnetpp.h>
#include <map>
#include "ManetRoutingBase.h"
#include "fgiproute.h"
#include "fgmessage/FGMessage.h"
#include "RoutingTableAccess.h"
#include "ICMPMessage.h"
#include "ICMPAccess.h"



class FG : public ManetRoutingBase {
private:

	char nodeName[50];
	ICMPAccess icmpAccess;

public:

	FG();
	~FG();

protected:

	bool is_init;
	typedef std::map<IPAddress,cPacketQueue> mapFGQueue;
	mutable mapFGQueue mapfgqueue;

	typedef std::map<IPAddress,bool> MapBool;

	typedef std::map<IPAddress,int> MapOfInt;
	typedef std::map<IPAddress,MapOfInt> RREQForwardedMap;
	mutable RREQForwardedMap rreqForwardedMap;


	typedef std::map<IPAddress,cMessage*> MapOfEvent;
	mutable MapOfEvent mapOfEvent;

	typedef std::map<IPAddress,double> TableOfNeighborAssociability;
	mutable TableOfNeighborAssociability tableOfNeighborAssociability;
	mutable TableOfNeighborAssociability tableOfNeighborPER;

	typedef std::map<IPAddress,int> NumOfHello;
	mutable NumOfHello numOfHello;

	typedef std::map<IPAddress,IPAddress> MapOfIP;


public: //members public, because have to be watched in TkEnv using WATCH macro

	typedef std::vector<IPAddress> IPVect;
	typedef std::map<IPAddress,IPVect> MapIPVect;
	typedef std::map<IPAddress,MapIPVect> RREQRecievedMap;
	//mutable RREQRecievedMap rreqRecievedMap;

	typedef std::map<IPAddress,mapFGQueue> SuspendedQueue;
	mutable SuspendedQueue suspendedQueue;

	typedef std::map<IPAddress,MapOfInt> HowManyTest;
	mutable HowManyTest howmanytest;

	typedef std::vector<cMessage*> VectorOfMessage;
	typedef std::map<IPAddress,VectorOfMessage> MapOfQueue;
	typedef std::map<IPAddress,MapOfQueue> MapOfCommodity;
	mutable MapOfCommodity mapOfCommodity;

	typedef std::map<IPAddress,MapOfIP> MapOfIPCommodity;
	mutable MapOfIPCommodity previusHop;

	typedef std::map<IPAddress,cStdDev> MapOfStatistic;
	mutable MapOfStatistic mapofstatistic;

	typedef std::map<IPAddress,double> MapOfDouble;
	mutable MapOfDouble waitingTime;
	mutable MapOfDouble nominalTXtime;


    friend std::ostream& operator<<(std::ostream&, const IPVect&);
    friend std::ostream& operator<<(std::ostream&, const MapIPVect&);
    friend std::ostream& operator<<(std::ostream&, const MapBool&);
    friend std::ostream& operator<<(std::ostream&, const MapOfIP&);
    friend std::ostream& operator<<(std::ostream&, const MapOfInt&);

protected:

	IPAddress myAddr;
	int if_id;
	int numDrop;
	InterfaceEntry* ie;
	MapBool isPD;
	MapBool isUpdated;
	MapOfInt howManyNewPD;
	MapOfInt consecutivePD;//#
	IRoutingTable *inet_irt;
	NotificationBoard *inet_nb;
	cMessage* helloEvent;
	cMessage* tableUpdate;
	cMessage* updateStat;
	double bitrate;
	int packetSize;
	//double nominalTXtime;
	//cStdDev nominalTXtime;
	double timeInQueue;
	//cStdDev collectedPER;
	int counter;
	int newCounter;
	IPRecordRouteOption lastRoute;


	//parameters red by omnetpp.ini
	double alpha1,alpha2,beta1;
	double helloPeriod;
	double newPDDelay;
	double newTestDelay;
	double weight_per;
	int    resetPeriod;
	double perThreshold;
	double updateStatPeriod;
	double perPenalty;

// statistic
	long numRREQsent;
	long numRREPsent;
	long numRTESTsent;
	long numRTESTAcksent;
	long numRERRsent;
	long numHELLOsent;
	long numControlSent;
	long numControlSentvar;

	long numRREQrec;
	long numRREPrec;
	long numRTESTrec;
	long numRTESTAckrec;
	long numRERRrec;
	long numHELLOrec;
	long numControlRec;
	long numControlRecvar;

	long numPD;
	long numTEST;
	long numErrorInPD;

	cOutVector controlPacketSent;
	cOutVector controlPacketRec;
	//cOutVector controlPacketSent2;
	//cOutVector controlPacketRec2;


//omnetpp API
	int numInitStages() const  {return 5;}
	virtual void handleMessage(cMessage *msg);
	virtual void finish();
	void initialize(int stage);

//FG methods
	void processPacketNoRoute(IPDatagram* );
	void processPacketUpdate(IPDatagram*);
	void processFGMessage(FGMessage*);
	void pathDiscovery(IPAddress&);
	void processRREQ(FGMessage*);
	void processRREP(FGMessage*);
	void processRERR(FGMessage*);
	void processHello(FGMessage*);
	void createAndSendRREP(FGMessage*);
	void forwardRREQ(FGMessage*);
	void forwardHello(FGMessage* hello);
	bool updateRoutingTable(FGMessage*);
	FGIPRoute* createRouteEntry(FGMessage*);
	void preventingLoopSend(FGMessage*);
	void forwardRREP(FGMessage*,const IPAddress&);
//	void forwardRREP(FGMessage*,IPAddress&);
	void sendAllPacket(IPAddress&);
	void updateRREPMetric(FGMessage *new_rrep,FGMessage *old_rrep,const IPAddress& destRREP);
	//abstract methods of ManetRoutingBase
	virtual void processLinkBreak(const cPolymorphic *details);
	virtual void processPromiscuous (const cPolymorphic *details){return;}
	const IPAddress& searchForDestination(cMessage*);
	int countBitLength(FGMessage*);
	void cancelAllEventInMapOfEvent();
	void sendHello();
	int countNumOfAssociatedNeighbor();
	void createAndSendRTEST(IPAddress& src, IPAddress& dest, int);
	void forwardRTEST(FGMessage* rtest);
	void forwardRTESTAck(FGMessage*);
	void processRTESTAck(FGMessage* m);
	void sendAllSuspendedPackets(IPAddress&,IPAddress&);
	void processRTEST(FGMessage*);
	void createAndSendRTESTAck(FGMessage*);
	bool searchForCommodity(cMessage*, IPAddress&, IPAddress&);
	cMessage* getAndRemoveTimerForCommodity(IPAddress&, IPAddress&, const char*);
	void cancelAllTimer();
	void processFailedTest(IPAddress&,IPAddress&);
	void createAndSendRERR(IPAddress&, IPAddress&);
	void forwardRERR(FGMessage *rerr);
	void resetCommodity(IPAddress&,IPAddress&);
	void putAllSuspendedPacketInQueueForSending(IPAddress&);
	void receiveChangeNotification(int category, const cPolymorphic*);
	virtual void processRadioState(const cPolymorphic*);
	//virtual void processMacQueue(const cPolymorphic*);
	virtual void processMacQueue(const cPolymorphic*);
	virtual void handleTableUpdate();
	virtual void updateGlobalStatistics();

};



#endif /* FG_H_ */


